#include "getopt.h"
#include <iostream>
#include <tuple>
#include <fstream>

#include <public/utils.h>
#include <graph.priv.h>
#include <config-fnt.h>

/* Options */
static const char* opts=":hv";
static const struct option opts_long[]=
{
	{"help", 0, nullptr, 'h'},
	{"version", 0, nullptr, 'v'},
	{nullptr, 0, nullptr, 0}
};

/* Print version information and exit */
void version(const char* name) {
	std::cout<<name<<" (" PACKAGE_NAME_LONG ") " PACKAGE_VERSION "\n";
	std::cout<<"Copyright (C) 2015-2016 " PACKAGE_ORG "\n";
	std::cout<<"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\n";
	std::cout<<"Written by: " PACKAGE_AUTHORS "\n";
	exit(0);
}
/* Print usage information and exit */
void usage(const char* name, int ecode) {
	if(ecode) {
		std::cerr<<"Try '"<<name<<" --help' for more information.\n";
		exit(ecode);
	}
	std::cout<<"Usage: "<<name<<" [OPTION]... FNT_FILE SWC_FILE\n";
	std::cout<<
		"Convert .fnt or .fntz files to SWC format.\n\n"
		"Options:\n"
		"  -h, --help       [OPTIONAL] Print this help, and do nothing else.\n"
		"  -v, --version    [OPTIONAL] Print version information and exit.\n\n"
		"FNT_FILE is a file with extension .fnt or .fntz. Output SWC file are\n"
		"written to SWC_FILE\n\n"
		"Report bugs to <" PACKAGE_BUGREPORT ">\n"
		PACKAGE_NAME_LONG " home page: <" PACKAGE_URL ">\n";
	exit(ecode);
}

int main(int argc, char* argv[]) {

	int opt;
	int prev_optind=optind;
	while((opt=getopt_long(argc, argv, opts, opts_long, nullptr))!=-1) {
		try {
			switch(opt) {
				case '?':
					throwError("unrecognized option '", argv[prev_optind], "'\n");
				case ':':
					throwError("option '", argv[prev_optind], "' requires an argument\n");
				case 'h':
					usage(argv[0], 0);
				case 'v':
					version(argv[0]);
				default:
					throwError("Unexpected error.\n");
			}
		} catch(std::exception& e) {
			std::cerr<<argv[0]<<": "<<e.what();
			usage(argv[0], -1);
		}
		prev_optind=optind;
	}

	std::vector<std::tuple<int64_t, int16_t, double, double, double, double, int64_t>> swc{};
	size_t nnrn=0;
	try {
		if(argc-optind!=2)
			throwError("Wrong number of positional arguments.");
		Graph gr=GraphPriv::alloc();
		auto gp=GraphPriv::get(gr);
		gp->loadFnt(argv[optind]);
		swc=gp->toSwc();
		nnrn=gr.trees().size();
		GraphPriv::free(gr);
	} catch(std::exception& e) {
		std::cerr<<argv[0]<<": "<<e.what();
		usage(argv[0], -1);
	}

	if(swc.size()==0) {
		std::cerr<<"Empty fnt file.\n";
		return 0;
	}

	try {
		std::ofstream ofs{argv[optind+1]};
		if(!ofs)
			throwError("Failed to open output file");
		ofs.precision(13);
		ofs.setf(std::ios::scientific);

		ofs<<"# Tracing result of "<<nnrn<<" neuron(s)\n";
		ofs<<"## generated by " PACKAGE_NAME_LONG " <" PACKAGE_URL ">\n\n";
		if(!ofs)
			throwError("Failed to write file");

		for(auto& t: swc) {
			ofs<<std::get<0>(t)<<' ';
			ofs<<std::get<1>(t)<<' ';
			ofs<<std::get<2>(t)<<' ';
			ofs<<std::get<3>(t)<<' ';
			ofs<<std::get<4>(t)<<' ';
			ofs<<std::get<5>(t)<<' ';
			ofs<<std::get<6>(t)<<'\n';
			if(!ofs)
				throwError("Failed to write file");
		}

		ofs.close();
		if(!ofs)
			throwError("Failed to close output file");

	} catch(std::exception& e) {
		std::cerr<<"Error while saving SWC file: "<<e.what();
		return -1;
	}
	return 0;
}

